<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>记账本</title>
    <script src="/js/vue/vue.js"></script>
    <script src="/js/vue/axios.js"></script>
    <script src="/js/vue/element-ui.js"></script>
    <script src="/js/util.js"></script>
    <style>
        @import url("/css/vue/element-ui.css");
        .el-message {
            min-width: 100px !important;
            max-width: 80% !important;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
        }

        :root {
            --primary: #4361ee;
            --secondary: #3f37c9;
            --success: #4cc9f0;
            --danger: #f72585;
            --warning: #f8961e;
            --light: #f8f9fa;
            --dark: #212529;
            --income: #06d6a0;
            --expense: #ef476f;
            --background: #f0f2f5;
            --card-bg: #ffffff;
            --text-primary: #333333;
            --text-secondary: #6c757d;
            --border: #e0e0e0;
            --pagination-active: #4361ee;
            --pagination-inactive: #d0d0d0;
        }

        body {
            background-color: var(--background);
            color: var(--text-primary);
            line-height: 1.6;
            padding-bottom: 80px;
        }

        .container {
            max-width: 100%;
            padding: 0 15px;
        }

        /* 头部样式 */
        header {
            background: linear-gradient(135deg, var(--primary), var(--secondary));
            color: white;
            padding: 20px 15px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            position: sticky;
            top: 0;
            z-index: 100;
        }

        .header-content {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .logo {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .logo i {
            font-size: 24px;
        }

        .logo h1 {
            font-size: 20px;
            font-weight: 600;
        }

        /* 新增的下拉菜单样式 */
        .nav-dropdown {
            position: absolute;
            right: 15px;
            display: inline-block;
            margin-right: 15px;
        }

        .nav-dropdown select {
            background-color: rgba(255, 255, 255, 0.2);
            color: white;
            border: 1px solid rgba(255, 255, 255, 0.3);
            border-radius: 5px;
            padding: 8px 12px;
            font-size: 14px;
            appearance: none;
            -webkit-appearance: none;
            -moz-appearance: none;
            cursor: pointer;
            padding-right: 30px;
            outline: none;
        }

        .nav-dropdown select option {
            background-color: var(--primary);
            color: white;
        }

        .nav-dropdown::after {
            content: "▼";
            font-size: 10px;
            color: white;
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            pointer-events: none;
        }

        .header-stats {
            display: flex;
            justify-content: space-around;
            margin-top: 15px;
            padding-top: 15px;
            border-top: 1px solid rgba(255, 255, 255, 0.2);
        }

        .stat-item {
            text-align: center;
        }

        .stat-label {
            font-size: 12px;
            opacity: 0.8;
        }

        .stat-value {
            font-size: 16px;
            font-weight: 600;
            margin-top: 5px;
        }

        .income-value {
            color: var(--income);
        }

        .expense-value {
            color: var(--expense);
        }

        /* 主内容区 */
        .main-content {
            padding: 20px 0;
        }

        .section-title {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding: 0 10px;
        }

        .section-title h2 {
            font-size: 18px;
            font-weight: 600;
        }

        .btn {
            background-color: var(--primary);
            color: white;
            border: none;
            border-radius: 50px;
            padding: 10px 20px;
            font-size: 14px;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 8px;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px rgba(67, 97, 238, 0.2);
        }

        .btn:hover {
            background-color: var(--secondary);
            transform: translateY(-2px);
        }

        .btn i {
            font-size: 14px;
        }

        /* 新增：筛选按钮和筛选面板样式 */
        .filter-section {
            margin-bottom: 20px;
            padding: 0 10px;
        }

        .filter-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }

        .filter-toggle {
            background-color: var(--light);
            color: var(--text-primary);
            border: 1px solid var(--border);
            border-radius: 50px;
            padding: 8px 16px;
            font-size: 14px;
            display: flex;
            align-items: center;
            gap: 8px;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .filter-toggle:hover {
            background-color: #e9ecef;
        }

        .filter-toggle.active {
            background-color: var(--primary);
            color: white;
            border-color: var(--primary);
        }

        .filter-panel {
            background-color: var(--card-bg);
            border-radius: 12px;
            padding: 20px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
            margin-top: 10px;
            display: none;
        }

        .filter-panel.active {
            display: block;
            animation: fadeIn 0.3s ease;
        }

        .filter-row {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            margin-bottom: 15px;
        }

        .filter-group {
            flex: 1;
            min-width: 150px;
        }

        .filter-group label {
            display: block;
            margin-bottom: 8px;
            font-size: 14px;
            font-weight: 500;
            color: var(--text-primary);
        }

        .filter-control {
            width: 100%;
            padding: 10px 12px;
            border: 1px solid var(--border);
            border-radius: 8px;
            font-size: 14px;
            background-color: var(--card-bg);
            transition: border 0.3s ease;
        }

        .filter-control:focus {
            outline: none;
            border-color: var(--primary);
        }

        .filter-actions {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            margin-top: 10px;
        }

        .btn-filter {
            padding: 8px 16px;
            border-radius: 8px;
            font-size: 14px;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .btn-filter-reset {
            background-color: var(--light);
            color: var(--text-primary);
            border: 1px solid var(--border);
        }

        .btn-filter-apply {
            background-color: var(--primary);
            color: white;
            border: 1px solid var(--primary);
        }

        .btn-filter:hover {
            opacity: 0.9;
            transform: translateY(-1px);
        }

        /* 记录列表 */
        .tableData-container {
            position: relative;
            overflow: hidden;
            border-radius: 12px;
            height: calc(100vh - 15px); /* 新增：设置固定高度 */
            overflow-y: auto; /* 新增：启用垂直滚动 */
        }

        .tableData-wrapper {
            min-height: 100%;
        }

        .tableData-list {
            display: flex;
            flex-direction: column;
            gap: 12px;
            width: 100%;
        }

        .record-item {
            background-color: var(--card-bg);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
            transition: transform 0.3s ease;
            position: relative;
            overflow: hidden;
            width: 100%;
        }

        .record-item:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
        }

        .record-content {
            flex: 1;
        }

        .record-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 8px;
        }

        .record-title {
            font-weight: 600;
            font-size: 16px;
        }

        .record-amount {
            font-weight: 700;
            font-size: 17px;
            transform: translate(100%, 0);
        }

        .income {
            color: var(--income);
        }

        .expense {
            color: var(--expense);
        }

        .record-details {
            display: flex;
            gap: 10px;
            font-size: 13px;
            color: var(--text-secondary);
        }

        .record-detail {
            display: flex;
            align-items: center;
            gap: 4px;
        }

        .record-actions {
            display: flex;
            gap: 12px;
        }

        .action-btn {
            width: 36px;
            height: 36px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            background-color: var(--light);
            color: var(--text-secondary);
            cursor: pointer;
            transition: all 0.2s ease;
            margin-top: 35px;
        }

        .action-btn:hover {
            background-color: var(--primary);
            color: white;
        }

        /* 新增：无限滚动加载指示器 */
        .loading-indicator {
            text-align: center;
            padding: 15px;
            color: var(--text-secondary);
            font-size: 14px;
        }

        /* 模态框 */
        .modal {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s ease;
        }

        .modal.active {
            opacity: 1;
            visibility: visible;
        }

        .modal-content {
            background-color: var(--card-bg);
            border-radius: 16px;
            width: 90%;
            max-width: 500px;
            max-height: 80vh;
            overflow-y: auto;
            transform: translateY(20px);
            transition: transform 0.3s ease;
            display: flex;
            flex-direction: column;
            position: relative; /* 添加相对定位 */
        }

        .modal.active .modal-content {
            transform: translateY(0);
        }

        .modal-header {
            padding: 20px;
            border-bottom: 1px solid var(--border);
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .modal-title {
            font-size: 18px;
            font-weight: 600;
        }

        .close-btn {
            background: none;
            border: none;
            font-size: 20px;
            color: var(--text-secondary);
            cursor: pointer;
        }

        .modal-body {
            padding: 20px;
            flex: 1;
            overflow-y: auto; /* 允许内容区域滚动 */
            padding-bottom: 80px;
        }

        .form-group {
            margin-bottom: 20px;
        }

        .form-group label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            font-size: 14px;
        }

        .form-control {
            width: 100%;
            padding: 12px 15px;
            border: 1px solid var(--border);
            border-radius: 10px;
            font-size: 15px;
            transition: border 0.3s ease;
        }

        .form-control:focus {
            outline: none;
            border-color: var(--primary);
        }

        .form-row {
            display: flex;
            gap: 15px;
        }

        .form-row .form-group {
            flex: 1;
        }

        .radio-group {
            display: flex;
            gap: 15px;
            margin-top: 8px;
            flex-wrap: wrap;
        }

        .radio-option {
            flex: 1;
            min-width: 100px;
        }

        .radio-option input {
            display: none;
        }

        .radio-option label {
            display: block;
            padding: 12px;
            background-color: var(--light);
            border-radius: 10px;
            text-align: center;
            cursor: pointer;
            transition: all 0.2s ease;
            border: 2px solid transparent;
        }

        .radio-option input:checked + label {
            background-color: rgba(67, 97, 238, 0.1);
            border-color: var(--primary);
            color: var(--primary);
            font-weight: 600;
        }

        .modal-footer {
            padding: 20px;
            border-top: 1px solid var(--border);
            display: flex;
            gap: 15px;
            position: sticky; /* 改为粘性定位 */
            bottom: 0;
            background-color: var(--card-bg); /* 背景色与模态框一致 */
            z-index: 10; /* 确保在最上层 */
            border-bottom-left-radius: 16px;
            border-bottom-right-radius: 16px;
        }

        .btn-cancel {
            background-color: var(--light);
            color: var(--text-primary);
            flex: 1;
        }

        .btn-submit {
            background-color: var(--primary);
            color: white;
            flex: 1;
            position: relative;
        }

        .empty-state i {
            font-size: 60px;
            color: #c0c0c0;
            margin-bottom: 20px;
        }

        .empty-state h3 {
            font-size: 18px;
            margin-bottom: 10px;
            color: var(--text-primary);
        }

        .empty-state p {
            color: var(--text-secondary);
            margin-bottom: 20px;
        }

        /* 响应式调整 */
        @media (max-width: 480px) {
            .header-content {
                flex-direction: column;
                align-items: flex-start;
                gap: 10px;
            }

            .logo h1 {
                font-size: 18px;
            }

            .form-row {
                flex-direction: column;
                gap: 0;
            }

            .record-details {
                flex-direction: column;
                gap: 4px;
            }

            .radio-option {
                min-width: auto;
            }

            .filter-row {
                flex-direction: column;
                gap: 10px;
            }

            .filter-group {
                min-width: 100%;
            }
        }

        /* 动画效果 */
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .record-item {
            animation: fadeIn 0.4s ease forwards;
            margin-bottom: 10px;
        }

        /* 添加在style部分的最后 */
        .toast-notification {
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: var(--primary);
            color: white;
            padding: 15px 25px;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            display: flex;
            align-items: center;
            gap: 10px;
            z-index: 2000;
            transform: translateX(150%);
            transition: transform 0.3s ease;
        }

        .toast-notification.show {
            transform: translateX(0);
        }

        .toast-notification.success {
            background-color: var(--success);
        }

        .toast-notification.error {
            background-color: var(--danger);
        }

        .toast-notification i {
            font-size: 20px;
        }

        /* 新增：Loading样式 */
        .loading-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(255, 255, 255, 0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 2000;
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s ease;
        }

        .loading-overlay.active {
            opacity: 1;
            visibility: visible;
        }

        .spinner {
            width: 40px;
            height: 40px;
            border: 4px solid rgba(67, 97, 238, 0.2);
            border-radius: 50%;
            border-top-color: var(--primary);
            animation: spin 0.8s linear infinite;
        }

        .btn-loading .spinner {
            width: 16px;
            height: 16px;
            border-width: 2px;
            margin-right: 8px;
        }

        .btn-loading {
            pointer-events: none;
            opacity: 0.8;
        }

        .action-btn-loading {
            pointer-events: none;
            opacity: 0.6;
        }

        .action-btn-loading::after {
            content: "";
            position: absolute;
            width: 16px;
            height: 16px;
            border: 2px solid rgba(67, 97, 238, 0.2);
            border-radius: 50%;
            border-top-color: var(--primary);
            animation: spin 0.8s linear infinite;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        .record-item-loading {
            opacity: 0.7;
            pointer-events: none;
        }

        .record-item-loading::after {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(255, 255, 255, 0.7);
            border-radius: 12px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .record-item-loading::before {
            content: "";
            position: absolute;
            z-index: 1;
            width: 20px;
            height: 20px;
            border: 2px solid rgba(67, 97, 238, 0.2);
            border-radius: 50%;
            border-top-color: var(--primary);
            animation: spin 0.8s linear infinite;
        }

        /* 优化金额显示样式 */
        .record-header {
            display: flex;
            justify-content: space-between;
            align-items: flex-start; /* 改为flex-start避免内容被压缩 */
            margin-bottom: 8px;
            gap: 10px; /* 添加间隙 */
        }

        .record-title {
            font-weight: 600;
            font-size: 16px;
            flex: 1; /* 允许标题占据更多空间 */
            min-width: 0; /* 重要：允许文本溢出处理 */
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .record-amount {
            font-weight: 700;
            font-size: 17px;
            flex-shrink: 0; /* 防止金额被压缩 */
            text-align: right;
            min-width: fit-content; /* 根据内容自适应宽度 */
        }

        /* 针对大金额的特殊处理 */
        .record-amount.large-amount {
            font-size: 15px; /* 大金额时稍微缩小字体 */
            letter-spacing: -0.2px; /* 稍微收紧字距 */
        }

        /* 超长金额的特殊处理 */
        .record-amount.very-large-amount {
            font-size: 14px;
            font-weight: 600;
        }

        /* 响应式调整：在小屏幕上进一步优化 */
        @media (max-width: 480px) {
            .record-header {
                gap: 8px;
            }

            .record-title {
                font-size: 15px;
                max-width: 60%; /* 限制标题最大宽度 */
            }

            .record-amount {
                font-size: 16px;
            }

            .record-amount.large-amount {
                font-size: 14px;
            }

            .record-amount.very-large-amount {
                font-size: 13px;
            }
        }

        /* 针对极端情况的处理 */
        @media (max-width: 360px) {
            .record-title {
                font-size: 14px;
                max-width: 55%;
            }

            .record-amount {
                font-size: 15px;
            }

            .record-amount.large-amount {
                font-size: 13px;
            }

            .record-amount.very-large-amount {
                font-size: 12px;
            }
        }
        /* 余额和日均掩码样式 */
        .stat-value {
            font-size: 16px;
            font-weight: 600;
            margin-top: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            cursor: pointer;
            transition: all 0.3s ease;
            padding: 4px 8px;
            border-radius: 6px;
        }

        .stat-value:hover {
            background-color: rgba(255, 255, 255, 0.1);
        }

        .eye-icon {
            font-size: 12px;
        }

        .stat-value:hover .eye-icon {
            opacity: 1;
        }

        .masked-amount {
            letter-spacing: 2px;
            font-family: 'Courier New', monospace;
        }

        .income-value {
            color: var(--income);
        }

        .expense-value {
            color: var(--expense);
        }

        .warning-value {
            color: var(--warning);
        }

        /* 响应式调整 */
        @media (max-width: 480px) {
            .stat-value {
                font-size: 14px;
                gap: 6px;
                padding: 3px 6px;
            }

            .eye-icon {
                font-size: 12px;
            }
        }
    </style>
</head>
<body>
<div id="app">
    <header>
        <div class="container">
            <div class="header-content">
                <div class="logo">
                    <h1>Coder-nav</h1>
                </div>
                <div class="nav-dropdown">
                    <select v-model="currentPage" @change="navigateToPage">
                        <option value="/">🍡&emsp;导航主页</option>
                        <option value="/memo">📌&emsp;记事本</option>
                        <option value="/cash">💰&emsp;记账本</option>
                        <option value="/page">🌈&emsp;动态页面</option>
                        <option value="/task">⏱️&emsp;定时任务</option>
                        <option value="/setting">⚙️&emsp;个人设置</option>
                        <option value="/readme">📖&emsp;帮助手册</option>
                        <option value="/doc.html">🛠️&emsp;接口文档</option>
                    </select>
                </div>
            </div>
            <div class="header-stats">
                <div class="stat-item">
                    <div class="stat-label">月消费</div>
                    <div class="stat-value expense-value">
                        <i class="eye-icon el-icon-view"></i>
                        <span>¥{{ monthSum }}</span>
                    </div>
                </div>
                <div class="stat-item">
                    <div class="stat-label">日均(饮食)</div>
                    <div class="stat-value warning-value">
                        <i class="eye-icon el-icon-view"></i>
                        <span>¥{{ dayFloodAvg }}</span>
                    </div>
                </div>
                <div class="stat-item">
                    <div class="stat-label">余额</div>
                    <div class="stat-value income-value" @click="toggleBalance">
                        <i class="eye-icon" :class="showBalance ? '' : 'el-icon-view'"></i>
                        <span v-if="showBalance">¥{{ cash }}</span>
                        <span v-if="!showBalance">{{ getMaskedAmount(cash) }}</span>
                    </div>
                </div>
            </div>
        </div>
    </header>

    <div class="container">
        <div class="main-content">
            <div class="section-title">
                <h2>最近收支记录</h2>
                <div style="display: flex; gap: 10px;">
                    <button class="filter-toggle" @click="toggleFilterPanel" :class="{ active: showFilterPanel }">
                        <span>筛选</span>
                    </button>
                    <button class="btn" @click="openAddModal" :class="{ 'btn-loading': addingRecord }">
                        <div class="spinner" v-if="addingRecord"></div>
                        <i class="fas fa-plus" v-else></i>
                        <span>{{ addingRecord ? '处理中...' : '新增记录' }}</span>
                    </button>
                </div>
            </div>

            <!-- 新增：筛选面板 -->
            <div class="filter-section">
                <div class="filter-panel" :class="{ active: showFilterPanel }">
                    <div class="filter-row">
                        <div class="filter-group">
                            <label for="filterFlag">收支类型</label>
                            <select id="filterFlag" v-model="filter.flag" class="filter-control">
                                <option value="">⚪ 全部</option>
                                <option v-for="item in flagList" :value="item.key">{{ item.value }}</option>
                            </select>
                        </div>
                        <div class="filter-group">
                            <label for="filterChannel">支付渠道</label>
                            <select id="filterChannel" v-model="filter.channel" class="filter-control">
                                <option value="">⚪ 全部</option>
                                <option v-for="item in channelList" :value="item.key">{{ item.value }}</option>
                            </select>
                        </div>
                        <div class="filter-group">
                            <label for="filterType">消费类型</label>
                            <select id="filterType" v-model="filter.type" class="filter-control">
                                <option value="">⚪ 全部</option>
                                <option v-for="item in typeList" :value="item.key">{{ item.value }}</option>
                            </select>
                        </div>
                    </div>
                    <div class="filter-row">
                        <div class="filter-group">
                            <label for="filterStartDate">开始日期</label>
                            <input type="date" id="filterStartDate" v-model="filter.startDate" class="filter-control">
                        </div>
                        <div class="filter-group">
                            <label for="filterEndDate">结束日期</label>
                            <input type="date" id="filterEndDate" v-model="filter.endDate" class="filter-control">
                        </div>
                        <div class="filter-group">
                            <label for="filterKeyword">消费备注</label>
                            <input type="text" id="filterKeyword" v-model="filter.remark" class="filter-control">
                        </div>
                    </div>
                    <div class="filter-actions">
                        <button class="btn-filter btn-filter-reset" @click="resetFilter">重置</button>
                        <button class="btn-filter btn-filter-apply" @click="applyFilter">筛选</button>
                    </div>
                </div>
            </div>

            <div class="tableData-container" @scroll="handleScroll" ref="scrollContainer">
                <div class="tableData-wrapper">
                    <div class="tableData-list">
                        <transition-group name="fade">
                            <div v-for="record in tableData" :key="record.id"
                                 class="record-item"
                                 :class="{ 'record-item-loading': deletingRecords[record.id] || editingRecordId === record.id }">
                                <div class="record-content">
                                    <div class="record-header">
                                        <div class="record-title" v-if="record.remark === ''">{{ record.typeDesc }}</div>
                                        <div class="record-title" v-if="record.remark !== ''">{{ record.typeDesc }}：{{record.remark}}</div>
                                        <div class="record-amount expense"
                                             :class="getAmountSizeClass(record.money)"
                                             v-if="record.flag === 0">
                                            💰 {{ formatMoneyDisplay(record.money) }}
                                        </div>
                                        <div class="record-amount income"
                                             :class="getAmountSizeClass(record.money)"
                                             v-if="record.flag === 1">
                                            💵 {{ formatMoneyDisplay(record.money) }}
                                        </div>
                                    </div>
                                    <div class="record-details">
                                        <div class="record-detail">
                                            <span>{{ record.channelDesc }}</span>
                                        </div>
                                        <div class="record-detail">
                                            🏷️
                                            <span>{{ formatDate(record.createDate) }}</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="record-actions">
                                    <div class="action-btn"
                                         @click="openEditModal(record.id)"
                                         :class="{ 'action-btn-loading': editingRecordId === record.id }">
                                        🖋️
                                    </div>
                                    <div class="action-btn"
                                         @click="deleteRecord(record.id)"
                                         :class="{ 'action-btn-loading': deletingRecords[record.id] }">
                                        🗑️
                                    </div>
                                </div>
                            </div>
                        </transition-group>
                        <div v-if="loading" class="loading-indicator">
                            加载中...
                        </div>
                        <div v-if="!hasMore" class="loading-indicator">
                            没有更多数据了
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 新增/编辑记录模态框 -->
    <div class="modal" :class="{ active: showModal }">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title">{{ modalTitle }}</h3>
                <button class="close-btn" @click="closeModal">&times;</button>
            </div>
            <div class="modal-body">
                <form id="recordForm">
                    <div class="form-row">
                        <div class="form-group">
                            <label for="recordDate">消费日期</label>
                            <input type="date" id="recordDate" v-model="infoCreateDate" class="form-control" required>
                        </div>
                    </div>

                    <div class="form-group">
                        <label for="recordType">消费类型</label>
                        <select id="recordType" v-model="infoType" class="form-control" required>
                            <option value="">请选择类型</option>
                            <option v-for="item in typeList" :value="item.key">{{ item.value }}</option>
                        </select>
                    </div>

                    <div class="form-group">
                        <label for="recordNote">消费备注（选填）</label>
                        <textarea id="recordNote" v-model="infoRemark" class="form-control" rows="1" placeholder="......"></textarea>
                    </div>

                    <div class="form-group">
                        <label for="recordAmount">消费金额（必填）</label>
                        <input type="number" id="recordAmount" v-model="infoMoney" class="form-control" placeholder="0.00" step="0.01" min="0" required>
                    </div>

                    <div class="form-group">
                        <label>收支类型</label>
                        <div class="radio-group">
                            <div class="radio-option" v-for="item in flagList" :key="item.value">
                                <input type="radio" name="inOut" :id="item.value" :value="item.key" v-model="infoFlag">
                                <label :for="item.value">{{ item.value }}</label>
                            </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <label>消费渠道</label>
                        <div class="radio-group">
                            <div class="radio-option" v-for="item in channelList" :key="item.value">
                                <input type="radio" name="channel" :id="item.value" :value="item.key" v-model="infoChannel">
                                <label :for="item.value">{{ item.value }}</label>
                            </div>
                        </div>
                    </div>

                </form>
            </div>
            <div class="modal-footer">
                <button class="btn btn-cancel" @click="closeModal" :disabled="savingRecord">取消</button>
                <button class="btn btn-submit" @click="saveRecord" :class="{ 'btn-loading': savingRecord }">
                    <div class="spinner" v-if="savingRecord"></div>
                    <span>{{ savingRecord ? '保存中...' : '保存' }}</span>
                </button>
            </div>
        </div>
    </div>
</div>
<div id="toast" class="toast-notification" :class="{ show: showToast, [toastType]: true }" v-if="showToast">
    <i class="fas" :class="toastIcon"></i>
    <span>{{ toastMessage }}</span>
</div>

<script>
    var curDate = new Date();
    new Vue({
        el: '#app',
        data: {
            tableData: [],
            showModal: false,
            editing: false,
            // 登录
            token: '',
            // 详情
            infoId: null,
            infoCreateDate: null,
            infoTitle: null,
            infoFlag: null,
            infoMoney: null,
            infoChannel: null,
            infoType: null,
            infoRemark: null,
            // 表格
            pageIndex: 1,
            pageSize: 20,
            totalCount: 0,
            cash: 0,
            monthSum: 0,
            dayFloodAvg: 0,
            channelList: [],
            flagList: [],
            typeList: [],
            // 新增的下拉菜单数据
            currentPage: '/cash',
            showToast: false,
            toastMessage: '',
            toastType: 'success',
            toastIcon: 'fa-check-circle',
            toastTimeout: null,
            // 新增：无限滚动相关
            loading: false,
            hasMore: true,
            scrollDebounce: null,
            // 新增：Loading状态
            globalLoading: false,
            savingRecord: false,
            addingRecord: false,
            deletingRecords: {}, // 记录删除状态的映射表
            editingRecordId: null, // 当前正在编辑的记录ID
            // 新增：筛选相关
            showFilterPanel: false,
            filter: {
                flag: '',
                channel: '',
                type: '',
                startDate: '',
                endDate: '',
                remark: ''
            },
            isFilterApplied: false,
            showBalance: false, // 控制余额显示隐藏
            maskChar: '·',      // 掩码字符
        },
        computed: {
            modalTitle() {
                return this.editing ? "编辑消费记录" : "新增消费记录";
            },
        },
        mounted:function() {
            // 检查Token
            this.checkToken()
        },
        methods: {
            formatDate(dateString) {
                const date = new Date(dateString);
                return `${date.getMonth() + 1}月${date.getDate()}日`;
            },
            openAddModal() {
                this.infoId = null;
                this.infoTitle = null;
                this.infoFlag = 0;
                this.infoMoney = null;
                this.infoChannel = 1;
                this.infoType = 1;
                this.infoRemark = null;
                this.editing = false;
                this.showModal = true;

                const today = new Date();
                const year = today.getFullYear();
                const month = String(today.getMonth() + 1).padStart(2, '0');
                const day = String(today.getDate()).padStart(2, '0');
                this.infoCreateDate = `${year}-${month}-${day}`;
            },
            openEditModal(id) {
                this.editingRecordId = id;
                this.getInfo(id);
                this.editing = true;
            },
            async saveRecord() {
                this.savingRecord = true;

                try {
                    await this.save();
                    this.closeModal();
                } catch (error) {
                    this.$message.error(error.message || '保存失败', 'error');
                } finally {
                    this.savingRecord = false;
                }
            },
            async deleteRecord(id) {
                if (!confirm('确定要删除这条记录吗？')) return;

                // 设置删除状态
                this.$set(this.deletingRecords, id, true);

                try {
                    await this.del(id);
                } catch (error) {
                    this.$message.error(error.message || '删除失败', 'error');
                } finally {
                    // 清除删除状态
                    this.$delete(this.deletingRecords, id);
                }
            },
            closeModal() {
                this.showModal = false;
                this.editing = false;
                this.editingRecordId = null;
            },
            handleScroll() {
                // 防抖处理
                clearTimeout(this.scrollDebounce);
                this.scrollDebounce = setTimeout(() => {
                    const container = this.$refs.scrollContainer;
                    // 检查是否滚动到底部
                    if (container.scrollTop + container.clientHeight >= container.scrollHeight - 50 && !this.loading && this.hasMore) {
                        this.loadMore();
                    }
                }, 100);
            },
            loadMore() {
                if (this.loading || !this.hasMore) return;

                this.loading = true;
                this.pageIndex++;

                axios.post('/cash/getPage', {
                    pageIndex: this.pageIndex,
                    pageSize: this.pageSize,
                    ...this.getFilterParams()
                }, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    const newData = response.data.data.data;
                    if (newData.length === 0) {
                        this.hasMore = false;
                    } else {
                        this.tableData = [...this.tableData, ...newData];
                    }
                    this.loading = false;
                }).catch((error) => {
                    console.error(error);
                    this.loading = false;
                    this.pageIndex--; // 加载失败，回退页码
                });
            },
            initData() {
                this.getCash()
                this.getMonthSum()
                this.getDayFloodAvg()
                this.getPage()
            },
            checkToken() {
                this.globalLoading = true;
                localStorage.setItem('jump', window.location.href);
                axios.get('/login/checkToken', {
                    params: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    if(!response.data.data) {
                        localStorage.setItem('token', '')
                        window.location.href = '/login'
                        return;
                    }
                    this.getChannelList()
                    this.getFlagList()
                    this.getTypeList()
                    this.initData()
                }).catch(error => {
                    console.error(error);
                }).finally(() => {
                    this.globalLoading = false;
                });
            },
            // 余额
            getCash() {
                axios.get('/cash/getCash', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.cash = response.data.data;
                });
            },
            // 月消费
            getMonthSum() {
                var date = new Date()
                axios.post('/cash/getSum', {
                    flags: [0],
                    year: date.getFullYear(),
                    month: date.getMonth() + 1,
                }, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.monthSum = response.data.data;
                });
            },
            // 日均(饮食)
            getDayFloodAvg() {
                var date = new Date()
                axios.post('/cash/getAvg', {
                    flags: [0],
                    types: [1],
                    year: date.getFullYear(),
                    month: date.getMonth() + 1,
                }, {
                    headers: {
                        token: localStorage.getItem('token')
                    },
                }).then((response) => {
                    this.$data.dayFloodAvg = response.data.data;
                });
            },
            // 分页
            getPage() {
                this.globalLoading = true;
                axios.post('/cash/getPage', {
                    pageIndex: this.pageIndex,
                    pageSize: this.pageSize,
                    ...this.getFilterParams()
                }, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.pageIndex = response.data.data.pageIndex;
                    this.$data.pageSize = response.data.data.pageSize;
                    this.$data.totalCount = response.data.data.totalCount;
                    this.$data.tableData = response.data.data.data;
                    this.hasMore = response.data.data.data.length >= this.pageSize;
                }).catch((response) => {
                    this.$message.error(response)
                }).finally(() => {
                    this.globalLoading = false;
                });
            },
            // 支付渠道
            getChannelList() {
                axios.get('/cash/getChannelList', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.channelList = response.data.data;
                }).catch((response) => {
                    this.$message.error(response)
                });
            },
            // 收支
            getFlagList() {
                axios.get('/cash/getFlagList', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.flagList = response.data.data;
                });
            },
            // 支付类型
            getTypeList() {
                axios.get('/cash/getTypeList', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.typeList = response.data.data;
                });
            },
            // 编辑
            save() {
                return new Promise((resolve, reject) => {
                    var infoCreateDate = new Date(this.$data.infoCreateDate);
                    axios.post('/cash/save', {
                        id: this.$data.infoId,
                        year: infoCreateDate.getFullYear(),
                        month: infoCreateDate.getMonth() + 1,
                        day: infoCreateDate.getDate(),
                        title: this.$data.infoTitle,
                        flag: this.$data.infoFlag,
                        money: this.$data.infoMoney,
                        channel: this.$data.infoChannel,
                        type: this.$data.infoType,
                        remark: this.$data.infoRemark,
                    }, {
                        headers: {
                            token: localStorage.getItem('token')
                        }
                    }).then((response) => {
                        if(response.data.code === 200) {
                            this.initData()
                            resolve(response);
                            this.$message.info('保存成功');
                        } else {
                            this.$message.error(response.data.msg);
                        }
                    }).catch((error) => {
                        this.$message.error(error);
                    });
                });
            },
            // 删除
            del(id) {
                return new Promise((resolve, reject) => {
                    axios.delete('/cash/delete', {
                        params: {
                            id: id
                        },
                        headers: {
                            token: localStorage.getItem('token')
                        }
                    }).then((response) => {
                        this.initData()
                        resolve(response);
                        this.$message.info('删除成功');
                    }).catch((error) => {
                        reject(error);
                        this.$message.error(error);
                    });
                });
            },
            // 详情
            getInfo(id) {
                this.globalLoading = true;
                axios.get('/cash/getInfo', {
                    params: {
                        id: id
                    },
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.infoId = response.data.data.id
                    this.$data.infoCreateDate = response.data.data.createDate
                    this.$data.infoTitle = response.data.data.title
                    this.$data.infoFlag = response.data.data.flag
                    this.$data.infoMoney = response.data.data.money
                    this.$data.infoChannel = response.data.data.channel
                    this.$data.infoType = response.data.data.type
                    this.$data.infoRemark = response.data.data.remark
                    this.showModal = true;
                }).catch((response) => {
                    this.$message.error(response)
                }).finally(() => {
                    this.globalLoading = false;
                    this.editingRecordId = null;
                });
            },
            // 新增的页面跳转方法
            navigateToPage() {
                if (this.currentPage && this.currentPage !== window.location.pathname) {
                    window.location.href = this.currentPage;
                }
            },
            // 新增：筛选相关方法
            toggleFilterPanel() {
                this.showFilterPanel = !this.showFilterPanel;
            },
            getFilterParams() {
                if (!this.isFilterApplied) {
                    return {};
                }
                const params = {};
                if (this.filter.flag !== '') params.flags = [this.filter.flag];
                if (this.filter.channel !== '') params.channels = [this.filter.channel];
                if (this.filter.type !== '') params.types = [this.filter.type];
                if (this.filter.startDate !== '') params.startDate = this.filter.startDate;
                if (this.filter.endDate !== '') params.endDate = this.filter.endDate;
                if (this.filter.remark !== '') params.remark = this.filter.remark;

                return params;
            },
            applyFilter() {
                this.isFilterApplied = true;
                this.pageIndex = 1;
                this.hasMore = true;
                this.getPage();
                this.showFilterPanel = false;
            },
            resetFilter() {
                this.filter = {
                    flag: '',
                    channel: '',
                    type: '',
                    startDate: '',
                    endDate: '',
                    remark: ''
                };
                this.isFilterApplied = false;
                this.pageIndex = 1;
                this.hasMore = true;
                this.getPage();
            },
            // 格式化金额显示
            formatMoneyDisplay(amount) {
                const numAmount = parseFloat(amount);

                // 如果金额大于等于10000，使用更紧凑的格式
                if (numAmount >= 10000) {
                    // 对于万元以上的金额，可以考虑使用更简洁的显示
                    if (numAmount >= 100000) {
                        return '¥' + (numAmount / 10000).toFixed(1) + '万';
                    }
                    return '¥' + numAmount.toFixed(0);
                }
                // 对于千元级别的金额，正常显示但去掉小数位
                if (numAmount >= 1000) {
                    return '¥' + numAmount.toFixed(0);
                }
                // 千元以下正常显示两位小数
                return '¥' + numAmount.toFixed(2);
            },
            // 根据金额大小返回对应的CSS类
            getAmountSizeClass(amount) {
                const numAmount = parseFloat(amount);
                if (numAmount >= 100000) {
                    return 'very-large-amount';
                } else if (numAmount >= 10000) {
                    return 'large-amount';
                }
                return '';
            },
            // 切换余额显示状态
            toggleBalance() {
                this.showBalance = !this.showBalance;
            },
            // 切换日均显示状态
            toggleAvg() {
                this.showAvg = !this.showAvg;
            },
            // 生成掩码金额
            getMaskedAmount(amount) {
                if (!amount && amount !== 0) return this.maskChar.repeat(4);

                const num = parseFloat(amount);
                if (isNaN(num)) return this.maskChar.repeat(4);

                // 根据金额长度生成相应长度的掩码
                const amountStr = num.toFixed(2);
                const maskLength = Math.max(4, amountStr.length); // 最少4个字符
                return this.maskChar.repeat(6);
            },
        },
    });
</script>
</body>
</html>